/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_and_model.h                                                        *
 ****************************************************************************/
#ifndef _ELISA_AND_MODEL_H
#define _ELISA_AND_MODEL_H

#include <iostream>
#include <set>
#include <vector>

#include "elisa_defs.h"
#include "elisa_variable.h"
#include "elisa_model.h"
#include "elisa_constraint.h"
#include "elisa_expression.h"


NAMESPACE_ELISA

/**
 * @file elisa_and_model.h
 * @brief Classe to handle and model.
 */

typedef std::set<ModelRep *> SetModelRep;

/**
 * @ingroup Constraint
 * @class CompoundModelRep
 * @brief Base class for compound model
 */
class CompoundModelRep : public ModelRep
{
public:
	/**
 	 * Constructor
 	 */
	CompoundModelRep();

	/**
 	 * Copy constructor
 	 */
	CompoundModelRep(const CompoundModelRep & right);

	/**
 	 * Destructor
 	 */
	virtual ~CompoundModelRep();

	/**
 	 * Assignment Operation
 	 */
	CompoundModelRep &
	operator=(const CompoundModelRep & right);

	/// @name Equality Operations
	//@{
	int
	operator==(const CompoundModelRep & right) const;

	int
	operator!=(const CompoundModelRep & right) const;
	//@}

	/**
 	 * add a model in the model
 	 * @param m the model to add
 	 */
	void addChild(ModelRep *m);

	/**
 	 * Serialize the constraint in a Stream
 	 * @param o the output stream
 	 */
	virtual bool serialize(std::ostream & os) = 0;

	/**
 	 * Deserialize the constraint in a Stream
 	 * @param i the input stream
 	 */
	virtual bool deserialize(std::istream & i) = 0;


	const SetModelRep & getModels() const
	{
		return _models;
	}

	/**
 	 * Compute the variable of the constraint in a set var
 	 * @param v the set of var where variables are put
 	 */
	void toVariables(VarImplSet & v)
	{
		SetModelRep::iterator it;
		for (it = _models.begin(); it != _models.end(); ++it) {
			(*it)->toVariables(v);
		}
	}

	/**
 	 * build the implementation of the variable in st
 	 */
	void initVariableImplementation(SearchTree & st)
	{
		SetModelRep::iterator it;
		for (it = _models.begin(); it != _models.end(); ++it) {
			(*it)->initVariableImplementation(st);
		}
	}

	/// @name Iterators over the set of all models
	//@{
	SetModelRep::iterator beginModel();

	SetModelRep::const_iterator const_beginModel() const;

	SetModelRep::iterator endModel();

	SetModelRep::const_iterator const_endModel() const;
	//@}

	/// @name Insertion of constraints in a model
	//@{
	void post(ModelRep & c);

	void post(ModelRep *c);

	void post(const SetModelRep & s);
	//@}

protected:
	SetModelRep _models;
};


/**
 * @class AndModel
 * support for and model
 */
class AndModel : public CompoundModelRep
{
public:
	/**
 	 * Constructor
 	 */
	AndModel();

	/**
 	 * Copy Constructor
 	 */
	AndModel(const AndModel & right);

	/**
 	 * Copy operator
 	 */
	AndModel &
	operator=(const AndModel & right);

	/**
 	 * Destructor
 	 */
	~AndModel();

	/// @name Equality Operations
	///@{
	int
	operator==(const AndModel & right) const;

	int
	operator!=(const AndModel & right) const;
	///@}

	/**
 	 * Print the model in the stream os
 	 */
	void print(std::ostream & os) const
	{
		os << "(";
		//SetModelRep::iterator it;
		SetModelRep::const_iterator it;
		if (_models.size() == 1) {
			it = _models.begin();
			(*it)->print(os);
		}

		if (_models.size() > 1) {
			it = _models.begin();
			(*it)->print(os);
			it++;
			for (; it != _models.end(); ++it) {
				os << " && " << std::endl;
				(*it)->print(os);
			}
		}
		os << ")";
	}

	/**
 	 * Serialize the CSP in a Stream
 	 * @param o the output stream
 	 */
	bool serialize(std::ostream & os);

	/**
 	 * Deserialize the CSP in a Stream
 	 * @param i the input stream
 	 */
	bool deserialize(std::istream & i);


	/**
 	 * Give the type of the model
 	 * @return a string that contains the name of the type
 	 */
	virtual std::string type() const
	{
		return "AndModel";
	}
};

END_NAMESPACE_ELISA

/**
 * build an model from the && operator
 * @relates CSP
 * @relates AndModel
 */
elisa::Model
operator&&(const elisa::Model & m1, const elisa::Model & m2);

/**
 * build an model from the && operator
 * @relates CSP
 * @relates AndModel
 */
elisa::Model& operator&=(elisa::Model & m1, const elisa::Model & m2);

#endif //ELISA_AND_MODEL_H
